package com.hlkj.warboot.configurer.util;

import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description: Redis持久化工具类
 * @Author: lixing
 * @Date: 2020/2/15 10:13
 */
public class RedisUtil {
    // 设置key永久有效【persist key】
    public static Boolean persist(RedisTemplate redisTemplate, String key) {
        return redisTemplate.persist(key);
    }

    // 设置key多少秒后过期【expire key 100】
    public static boolean expire(RedisTemplate redisTemplate, String key, long time) {
        return redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }

    // 设置key在某个日期上过期
    public static boolean expire(RedisTemplate redisTemplate, String key, Date date) {
        return redisTemplate.expireAt(key, date);
    }

    // 查询key的生命周期，单位：秒【ttl key】
    public static Long getExpire(RedisTemplate redisTemplate, String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    // 删除key【del key】
    public static boolean del(RedisTemplate redisTemplate, String key) {
        return redisTemplate.delete(key);
    }

    public static long del(RedisTemplate redisTemplate, String... keys) {
        Set<String> kSet = Stream.of(keys).collect(Collectors.toSet());
        return redisTemplate.delete(kSet);
    }

    public static long del(RedisTemplate redisTemplate, Collection<String> keys) {
        Set<String> kSet = new HashSet<>(keys);
        return redisTemplate.delete(kSet);
    }

    // 检查key是否存在【keys key】
    public static Boolean exists(RedisTemplate redisTemplate, String key) {
        return redisTemplate.hasKey(key);
    }

    /*
     * @Description TODO ========================================================================================地理空间
     */
    // 向自定义地理空间（key）中添加成员（member），其坐标为（x,y） 【geoadd key x y member】
    public static long geoadd(RedisTemplate redisTemplate, String key, Double x, Double y, String member) {
        return redisTemplate.opsForGeo().add(key, new Point(x, y), member);
    }

    // 从向自定义地理空间（key）中查询成员列表（members）的坐标信息 【geopos key member】
    public static List<Point> geopos(RedisTemplate redisTemplate, String key, String[] members) {
        return redisTemplate.opsForGeo().position(key, members);
    }

    // 在自定义地理空间（key）中，以自定义坐标（x、y）为圆心、radius为半径进行搜索，上线count条 【georadius key x y 10 km withdist withcoord asc count 10】
    public static GeoResults<RedisGeoCommands.GeoLocation<String>> georadius(RedisTemplate redisTemplate, String key, Double x, Double y, int radius, int count) {
        Point point = new Point(x, y);
        Distance distance = new Distance(radius, Metrics.KILOMETERS);
        Circle circle = new Circle(point, distance);
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(count);
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius(key, circle, args);
        return results;
    }

    // 在自定义地理空间（key）中，以坐标member为圆心、radius为半径进行搜索，上线count条 【georadius key member 10 km withdist withcoord asc count 10】
    public static GeoResults<RedisGeoCommands.GeoLocation<String>> georadiusbymember(RedisTemplate redisTemplate, String key, String member, int radius, int count) {
        Distance distance = new Distance(radius, Metrics.KILOMETERS);
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(count);
        return redisTemplate.opsForGeo().radius(key, member, distance, args);
    }

    // 获取两个成员坐标间的直线距离 【geodist key member1 member2 km】
    public static Distance geodist(RedisTemplate redisTemplate, String key, String member1, String member2) {
        return redisTemplate.opsForGeo().distance(key, member1, member2, RedisGeoCommands.DistanceUnit.KILOMETERS);
    }

    /*
     * @Description TODO =========================================================================================基数统计
     */
    // 添加key 【pfadd key value】
    public static long pfadd(RedisTemplate redisTemplate, String key, String value) {
        return redisTemplate.opsForHyperLogLog().add(key, value);
    }

    // 将keys合并到key 【pfmerge key key1 key2】
    public static long pfunion(RedisTemplate redisTemplate, String key, String[] keys) {
        return redisTemplate.opsForHyperLogLog().union(key, keys);
    }

    // 获取key的基数 【pfcount key】
    public static long pfcount(RedisTemplate redisTemplate, String key) {
        return redisTemplate.opsForHyperLogLog().size(key);
    }

    /*
     * @Description TODO ============================================================================================位图
     */
    // 添加key 【setbit key value】
    public static Boolean setbit(RedisTemplate redisTemplate, String key, long index, boolean value) {
        return redisTemplate.opsForValue().setBit(key, index, value);
    }

    // 根据索引查询key的value 【getbit key index】
    public static Boolean getBit(RedisTemplate redisTemplate, String key, long index) {
        return redisTemplate.opsForValue().getBit(key, index);
    }

    // 统计key中value=1的数量大小 【bitcount key】
    public static long getBitSize(RedisTemplate redisTemplate, String key) {
        return redisTemplate.opsForValue().size(key);
    }

    /*
     * @Description TODO ============================================================================================SET
     */
    // 删除集合元素 【srem|zrem key value】
    public static long rem(RedisTemplate redisTemplate, String key, String value) {
        return redisTemplate.opsForSet().remove(key, value);
    }

    // 集合大小 【scard|zcard key】
    public static long card(RedisTemplate redisTemplate, String key) {
        return redisTemplate.opsForSet().size(key);
    }

    //
    // 添加key 【sadd key value】
    public static long sadd(RedisTemplate redisTemplate, String key, String value) {
        return redisTemplate.opsForSet().add(key, value);
    }

    // 判断value是否存在 【sismember key value】
    public static boolean sismember(RedisTemplate redisTemplate, String key, String value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    // 查询集合所有成员 【smembers key】
    public static Set smembers(RedisTemplate redisTemplate, String key) {
        return redisTemplate.opsForSet().members(key);
    }

    // 随机获取集合中的count个成员 【srandmember key count】
    public static List<String> srandmember(RedisTemplate redisTemplate, String key, int count) {
        return redisTemplate.opsForSet().randomMembers(key, count);
    }

    // 随机删除并返回集合中的count个成员 【spop key count】
    public static List<String> spop(RedisTemplate redisTemplate, String key, int count) {
        return redisTemplate.opsForSet().pop(key, count);
    }

    // 并集
    public static Object sunion(RedisTemplate redisTemplate, String keys, String newKey) {
        if (StrUtil.isEffective(newKey)) {
            // 求并集存入newkey集合，并返回集合长度 【sunionstore destination key key1..keyn】
            return redisTemplate.opsForSet().unionAndStore(Arrays.asList(keys.split(",")), newKey);
        }
        // 求并集并返回集合 【sunion key key1..keyn】
        return redisTemplate.opsForSet().union(Arrays.asList(keys.split(",")));
    }

    // 交集
    public static Object sinter(RedisTemplate redisTemplate, String keys, String newKey) {
        if (StrUtil.isEffective(newKey)) {
            // 求并集存入newkey集合，并返回集合长度
            return redisTemplate.opsForSet().intersectAndStore(Arrays.asList(keys.split(",")), newKey);
        }
        // 求并集并返回集合
        return redisTemplate.opsForSet().intersect(Arrays.asList(keys.split(",")));
    }

    // 差集
    public static Object sdiff(RedisTemplate redisTemplate, String keys, String newKey) {
        if (StrUtil.isEffective(newKey)) {
            // 求并集存入newkey集合，并返回集合长度
            return redisTemplate.opsForSet().differenceAndStore(Arrays.asList(keys.split(",")), newKey);
        }
        // 求并集并返回集合
        return redisTemplate.opsForSet().difference(Arrays.asList(keys.split(",")));
    }

    /*
     * @Description TODO ===========================================================================================ZSET
     */
    // 添加元素 【zadd key score value】
    public static boolean zsadd(RedisTemplate redisTemplate, String key, String value, Double score) {
        return redisTemplate.opsForZSet().add(key, value, score);
    }

    // 递增score 【zincrby key 1 value 】
    public static Double zincrby(RedisTemplate redisTemplate, String key, String value, Double score) {
        return redisTemplate.opsForZSet().incrementScore(key, value, score);
    }

    // key与多个otherkey的并集存储到newKey中
    public static long zunionstore(RedisTemplate redisTemplate, String key, String otherKeys, String newKey) {
        return redisTemplate.opsForZSet().unionAndStore(key, Arrays.asList(otherKeys.split(",")), newKey);
    }

    // 按照score倒序排列输出
    public static Set zrevrange(RedisTemplate redisTemplate, String key, double min, double max, long offset, long count) {
        if (offset < 0 || count <= 0) {
            return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, min, max);
        } else {
            return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, min, max, offset, count);
        }
    }

    /*
     * @Description TODO ===========================================================================================LIST
     */
    // 添加元素
    public static long lpush(RedisTemplate redisTemplate, String key, String value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    // 从左弹出元素
    public static Object lpop(RedisTemplate redisTemplate, String key) {
        return redisTemplate.opsForList().leftPop(key, 10, TimeUnit.SECONDS);
    }

    // 从右弹出元素
    public static Object rpop(RedisTemplate redisTemplate, String key) {
        return redisTemplate.opsForList().rightPop(key, 10, TimeUnit.SECONDS);
    }

    /*
     * @Description TODO =========================================================================================String
     */
    public static void setStr(RedisTemplate redisTemplate, String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public static void getStr(RedisTemplate redisTemplate, String key) {
        redisTemplate.opsForValue().get(key);
    }

    public static void incr(RedisTemplate redisTemplate, String key) {
        redisTemplate.opsForValue().increment(key);
    }

    public static void decy(RedisTemplate redisTemplate, String key) {
        redisTemplate.opsForValue().decrement(key);
    }

}
